//
//  TCGirdRender.swift
//  onemeetingmac
//
//  Created by 张衡 on 2020/6/24.
//  Copyright © 2020 onemeeting. All rights reserved.
//

import Foundation

class TCGirdRender: NSObject {
    private static var _shared:TCGirdRender?
    class func shared() -> TCGirdRender {
        guard let instance = _shared else {
            _shared = TCGirdRender()
            return _shared!
        }
        return instance
    }
    
    private override init() {}
    class func destory() {
        TCGirdRender.shared().renderer.removeSub()
        _shared = nil
    }
    
    var upMenu:NSMenu?
    
    var scene:TRTCScene = .meeting
    
    func canAdd() -> Bool {
        return self.renderer.infoList.count < self.max()
    }
    
    //设定最大人数
    func max() -> Int {
        return 4//(self.scene == .meeting) ? Td.sh().usr.max:4//(3*3):4
    }
    
    var indexLast:Int {
        return self.renderer.viewList.indexLast
    }
    //初始化数据
    func setup(dataList:[UserInfo]) {
        self.renderer.removeSub()
        for (inx,val) in dataList.enumerated(){
            if (inx+1) <= self.max() {
                let inx = val.userId?.isCurret() == true ? 0:nil
                self.renderer.addNew(uInfo: val, inx: inx)
            }
        }
        self.renderer.reloadData()
        self.checkFocus()
    }
    
    
    func checkFocus() {
        let focusid = Td.sh().cloud.focusId
        if focusid != mt_none {
            TCGirdRender.shared().renderer.swapt(focusId: focusid)
        }
    }
    
    func removeSub()  {
        self.renderer.removeSub()
    }
    
    func addNot()  {
        //移出用户
        NotificationCenter.default.addObserver(self,selector: #selector(deleteUser(not:)),name: MTDeleteUsersNotification,object: nil)
           
        //添加用户
        NotificationCenter.default.addObserver(self,selector: #selector(addUser(not:)),name:  MTAddUsersNotification,object: nil)
        
        //window窗口变化
        NotificationCenter.default.addObserver(self, selector: #selector(windowDidResize(notification:)), name: NSWindow.didResizeNotification, object: nil)
        
        //用户状态
        NotificationCenter.default.addObserver(self, selector: #selector(userStatuChange(not:)), name: MTUserStateNotification, object: nil)
        
        //放下全部举手
        NotificationCenter.default.addObserver(self, selector: #selector(allDownHandUp(not:)), name: MTADownHandUpNotification, object: nil)
        
        //共享流接受
        NotificationCenter.default.addObserver(self, selector: #selector(reiveSubSteam(not:)), name: MTSubStreamNotification, object: nil)
        
        //焦点
        NotificationCenter.default.addObserver(self,selector: #selector(focusChange(not:)),name:  MTFocusChangeNotification,object: nil)
        
        //切换并排模式
        NotificationCenter.default.addObserver(self,selector: #selector(hasSplit(not:)),name:  MTHasSplitNotification,object: nil)
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    lazy var renderer: TCGirdView = {
        let view = TCGirdView.init(infoList: [])
        view.touchDelegate = self
        view.wantsLayer = true
        view.layer?.backgroundColor = color_rgba(r: 40, g: 42, b: 48).cgColor
        return view
    }()
    
    func current() -> TCVideoView? {
        let inx = TCGirdRender.shared().renderer.infoList.firstIndex { (info) -> Bool in
            return info.userId==Td.sh().params.userId
        }
        if inx != nil {
            return TCGirdRender.shared().renderer.viewList[inx!]
        }
        return nil
    }
    
}

extension TCGirdRender {
    @objc func addUser(not:Notification) {
        guard let info = not.object as? UserInfo else {
            return
        }
        if renderer.hasSpalt == false {
            self.add(uInfo: info)
        }
     }
      
     @objc func deleteUser(not:Notification) {
        guard let info = not.object as? UserInfo else {
            return
        }
        if renderer.hasSpalt == false {
            self.delete(uInfo: info)
        }
     }
    
     func add(uInfo:UserInfo) {
        let isok = self.renderer.infoList.contains { (info) -> Bool in
            return (uInfo.userId==info.userId)
        }
        if isok == false {
            if self.canAdd() {
                self.renderer.addNew(uInfo: uInfo, inx: nil)
                let view = self.renderer.viewList.last
                guard let uid = uInfo.userId else {
                    return
                }
                if uid.isCurret() == false {
                    TXLiteManager.shared().startRemoteView(userId: uid, view: view!.videoView)
                }else {
                    TXLiteManager.shared().startLocalPreview(view: view!.videoView)
                }
            }
        }
    }
     
    func delete(uInfo:UserInfo) {
        
        let isok = self.renderer.infoList.contains { (info) -> Bool in
            return (uInfo.userId==info.userId)
        }
        if isok == true {
            let inx = self.renderer.infoList.firstIndex(where: { (info) -> Bool in
                return (info.userId==uInfo.userId)
            })
            if inx != nil {
                self.renderer.remove(inx: inx!)
                
                if uInfo.userId!.isCurret() {
                    TXLiteManager.shared().stopLocalPreview()
                }else {
                    TXLiteManager.shared().stopRemoteView(userId: uInfo.userId!)
                }
                
                //参会数量大于显示视频数量，补视频
                if Td.sh().scene == .meeting {
                    let max = self.max()
                    if (Td.sh().usr.remote.count+1) >= max {
                        let uInfo = Td.sh().usr.remote.last
                        self.renderer.addNew(uInfo: uInfo!, inx: nil)
                        self.renderer.reloadDataPart(subscripts: [self.indexLast],infoList: self.renderer.infoList)
                    }
                }
                
            }
        }
    }
}


extension TCGirdRender {
    @objc func windowDidResize(notification:Notification) {
        self.renderer.reloadMode()
    }
    
    func modifyName(mode:UserMode) {
        let userID = mode.userId ?? Td.sh().params.userId!
        IMEngine.shared.getUsersInfo(groupIDs:  [userID], succ: { (result) in
            let uInfo = result.first { (info) -> Bool in
                return info.userID==userID
            }
            let firstIndex = self.renderer.infoList.firstIndex { (info) -> Bool in
                return info.userId==userID
            }
            if let index = firstIndex,let kInfo = uInfo {
                if let name = kInfo.nickName {
                    self.renderer.infoList[index].nickName = name
                }else {
                    self.renderer.infoList[index].nickName = mode.nickName ?? "..."
                }
                self.renderer.reloadDataNoVideo()
            }
            
        }) { (code, name) in
            
        }
    }
    
    @objc func allDownHandUp(not:Notification) {
        if not.object as? String == ReloadNotification {
            self.renderer.reloadDataNoVideo()
            return
        }
    }
    
    @objc func userStatuChange(not:Notification) {
        guard let mode = not.object as? UserMode else {
            return
        }
        
        let index = self.renderer.infoList.firstIndex { (info) -> Bool in
            let userid = mode.userId ?? Td.sh().params.userId!
            return info.userId == userid
        }
        
        if let inx = index {
            if let isHandUp = mode.isHandUp {
                self.renderer.infoList[inx].isHandUp = isHandUp
            }
            if let isMute = mode.isMute {
                self.renderer.infoList[inx].isMute = isMute
            }
            if let isVdOpen = mode.isVdOpen {
                self.renderer.infoList[inx].isVdOpen = isVdOpen
            }
            if mode.nickName != nil {
                self.modifyName(mode: mode)
            }
            self.renderer.reloadDataNoVideo()
        }
        
        
    }
    
    @objc func reiveSubSteam(not:Notification) {
        guard let mode = not.object as? StreamMode else {
            return
        }
        
        if mode.available {
            MTNot.postHasUser(isok: false)
            var info = UserInfo.init()
            info.userId = mode.userId
            info.streamType = .sub
            info.nickName = "窗口共享"
            self.renderer.enterScreen(infoList: [info])
        }else {
            self.renderer.exitScreen()
        }
        
    }
    
    @objc func focusChange(not:Notification) {
        guard let focusId = not.object as? String else { return  }
        if Td.sh().sd.isSding && TCGirdRender.shared().renderer.isPic2pic == true {
            TCGirdRender.shared().renderer.pic2picInitOrFocusChange()
        }else {
            TCGirdRender.shared().renderer.swapt(focusId: focusId)
            TCGirdRender.shared().renderer.checkStatus()
        }
        
    }
    
    @objc func hasSplit(not:Notification) {
        guard let isok = not.object as? Bool else {
            return
        }
        TCGirdRender.shared().renderer.hasSpalt = isok
        if let window = self.renderer.window {
            if isok {
                TrtcEngine.addStandDFs(inWindow: window)
            }else {
                TrtcEngine.removeDFs(inWindow: window)
                TCGirdRender.shared().renderer.reloadData()
            }
        }
        
    }
    
    func createItems(info:UserInfo) -> [ZHMenuItem] {
        var item:[ZHMenuItem] = []
        let focus =  info.userId?.isFocusId()==true ? "取消焦点":"设定焦点"
        var menuNames = [focus]
        if info.userId?.isCurret() != true {
            menuNames.append("移出")
        }
        
        for (inx,val) in menuNames.enumerated() {
            let menu = ZHMenuItem.init(title: val, keyEquivalent: "", saction: { (item) in
                self.menuAction(senber:item as! ZHMenuItem, info: info)
            },size:NSSize.init(width: 120, height: 22))
            menu.kstate = .off
            menu.tag = inx
            menu.state = .off
            menu.target = self
            item.append(menu)
        }
        return item
    }
    
    func menuAction(senber:ZHMenuItem, info: UserInfo) {
        self.upMenu?.cancelTracking()
        if let userid = info.userId {
            switch senber.tag {
            case 0:
                let focusid = info.userId?.isFocusId() == true ? mt_none:userid
                IMcmd.shared.focusUser(userId: focusid)
                MTNot.postFocusID(userID: focusid)
            case 1:
                IMcmd.shared.kick(userId: userid)
            default:
                break
            }
        }
        
    }
    
    func moreView(senber:NSView ,info:UserInfo) {
        let menu = NSMenu.init()
        menu.isDark = true
        self.createItems(info: info).forEach { (item) in
            menu.addItem(item)
        }
        menu.needsUpdate()
        self.upMenu = menu
        let p = NSPoint(x: 0, y: senber.frame.height+10)
        menu.popUp(positioning: nil, at: p, in: senber)
    }
}

extension TCGirdRender:TCGirdViewDelegate {
    func trtcGird_mute(girdView: TCGirdView, row: Int, view: TCVideoView, btn: ZHButton) {
        if self.renderer.isSding == false {
            let info = girdView.infoList[row]
            guard let userid =  info.userId else {
                return
            }
            if userid.isCurret() {
                Td.sh().lc.isMute = !info.isMute
                MTNot.postNotMute(isok: !info.isMute)
            }else {
                IMcmd.shared.muteUser(userId: userid, isok: !info.isMute)
            }
        }
        
        
    }
    
    func trtcGird_more(girdView: TCGirdView, row: Int, view: TCVideoView, btn: ZHButton) {
        if self.renderer.isSding == false {
            self.moreView(senber: btn , info: view.data!)
        }
        
    }
    
    func trtcGird_hand(girdView: TCGirdView, row: Int, view: TCVideoView, icon: KIcon) {
        if self.renderer.isSding == false {
            if String.isHostId() {
                let info = girdView.infoList[row]
                guard let userid =  info.userId else {
                    return
                }
                IMcmd.shared.downUserHand(userId: userid)
                view.isHandup = false
            }
        }
        
    }
    
    func trtcGird_onClick(girdView: TCGirdView, row: Int, view: TCVideoView, event: NSEvent) {
        if self.renderer.isSding == false {
             if girdView.mode == .speaker && row != 0 {
                let event_location = event.locationInWindow
                let point = girdView.convert(event_location, to:NSApplication.shared.mainWindow?.contentView)

                let menuVc = ZMenuViewController()
                menuVc.indxTap = { indx in
                   
                }
                menuVc.dataList = ["设定焦点","移出","设置联席主持人"]
                let lk = Lk.create(controller: menuVc)
                lk.show(relativeTo: point, of: view)
            }
        }
    }
    func trtcGird_donbleClick(girdView: TCGirdView, row: Int, view: TCVideoView, event: NSEvent) {
        if self.renderer.isSding == false {
            if row != 0 && girdView.mode == .speaker {
                girdView.infoList.swapAt(0, row)
                girdView.reloadDataPart(subscripts: [0,row], infoList: girdView.infoList)
            }else if girdView.mode == .gird {
                let info = girdView.infoList[row]
                girdView.specifyUid = girdView.specifyUid == nil ? info.userId:nil
                girdView.inFullForm(first:girdView.specifyUid)
                view.setFullTop(isOK: girdView.specifyUid != nil)
            }
        }
        
         
    }
    func trtcGird_mouseEnter(girdView: TCGirdView, row: Int, view: TCVideoView) {
        if self.renderer.isSding == false  {
            if girdView.infoList.count > 1 && String.isHostId()   {
                view.isHover = true
                view.setFullTop(isOK: girdView.specifyUid != nil)
            }
            
        }
        
    }
    func trtcGird_mouseExit(girdView: TCGirdView, row: Int, view: TCVideoView) {
        if self.renderer.isSding == false {
            if girdView.infoList.count > 1 && String.isHostId() {
                view.isHover = false
            }
        }
    }
}


extension Array {
    subscript (safe index: Int) -> Element? {
        return (0..<count).contains(index) ? self[index] : nil
    }
    
    var indexLast: Int {
        return self.count-1
    }
}
